package com.cj.bus.common.config;


import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ValidationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import com.cj.bus.common.entity.ResponseEntity;
import com.cj.bus.common.entity.ResponseHelper;
import com.cj.bus.common.enums.ErrorCodeEnum;
import com.cj.bus.common.ex.BaseException;
import com.cj.bus.common.ex.BusinessException;
import com.cj.bus.common.utils.SpringContextUtil;

/** */
@Configuration
@RestControllerAdvice
public class GlobalExceptionHandler {
	private Logger logger = LoggerFactory.getLogger(getClass());

	@ExceptionHandler(BusinessException.class)
	public ResponseEntity<String> handleBusException(HttpServletRequest request, BusinessException e) {
		logger.error("BusEx,ERROR_CODE:"+e.getExceptionCode()+"，MSG："+e.getExceptionDetail(), e);
		return outputExceptionMsg(e,e.getExceptionCode(),e.getMessage());
	}

	@ExceptionHandler(BaseException.class)
	public ResponseEntity<String> handleBaseException(HttpServletRequest request, BaseException e) {
		logger.error("BaseEx,ERROR_CODE:"+e.getExceptionCode()+"，MSG："+e.getExceptionDetail(), e);
		return outputExceptionMsg(e,e.getExceptionCode(),e.getMessage());
	}

	@ExceptionHandler(IOException.class)
	public ResponseEntity<String> handleIOException(HttpServletRequest request, IOException e) {
		logger.error("IOException异常，请求参数：" + e.getMessage(), e);
		return outputExceptionMsg(e,ErrorCodeEnum.IO_ERROR.getCode(),ErrorCodeEnum.IO_ERROR.getDesc());
	}
	
	@ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<String> handleNoHandlerFoundException(NoHandlerFoundException e) {
        return ResponseHelper.failServerError(ErrorCodeEnum.NOT_FOUND.getCode(),"访问的资源不存在");
    }
	
	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public ResponseEntity<String> handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
	  return outputExceptionMsg(e,ErrorCodeEnum.NOT_SUPORT_REQUEST_TYPE.getCode(),"不支持的访问类型");
    }
	
	@ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handleIllegalArgumentException(HttpServletRequest request, IllegalArgumentException e) {
	    logger.error("参数错误："+ getStackTrace(e));
        return outputExceptionMsg(e,ErrorCodeEnum.PARA_ERROR.getCode(),e.getMessage());
    }

	@ExceptionHandler(ValidationException.class)
	public ResponseEntity<String> handleIllegalValidationException(HttpServletRequest request, ValidationException e) {
		logger.error("参数校验错误："+ getStackTrace(e));
		return ResponseHelper.failServerError(ErrorCodeEnum.PARA_ERROR.getCode(),e.getMessage());
	}

	/**
	 * validation异常捕获处理 （可能是MethodArgumentNotValidException或 BindException）
	 * @param e  MethodArgumentNotValidException 异常
	 * @return com.example.common.bean.JsonResult
	 */
	@ExceptionHandler(value = MethodArgumentNotValidException.class)
	public ResponseEntity<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
		List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
		StringBuilder sb = new StringBuilder();
		allErrors.forEach(objectError -> sb.append(objectError.getDefaultMessage()).append(";"));
		return ResponseHelper.failServerError(ErrorCodeEnum.PARA_ERROR.getCode(),sb.toString());
	}

	@ExceptionHandler(value = BindException.class)
	public ResponseEntity<String> handleBindException(BindException e) {
		FieldError fieldError = e.getFieldError();
		StringBuilder sb = new StringBuilder();
		sb.append(fieldError.getField()).append("=[").append(fieldError.getRejectedValue()).append("]")
				.append(fieldError.getDefaultMessage());
		return ResponseHelper.failServerError(ErrorCodeEnum.PARA_ERROR.getCode(),sb.toString());
	}

	@ExceptionHandler(Exception.class)
	public ResponseEntity<String> handleException(HttpServletRequest request, Exception e) {
		logger.error("Exception异常:" + getStackTrace(e),e);
		return outputExceptionMsg(e, ErrorCodeEnum.SYS_ERROR.getCode(),"服务器繁忙");
	}

	private ResponseEntity<String> outputExceptionMsg(Exception e, Integer errorCode, String errorMsg){

		if(SpringContextUtil.isProd() || SpringContextUtil.isTest()){
			return ResponseHelper.failServerError(errorCode,errorMsg);
		}else{
			return ResponseHelper.failServerError(errorCode, errorMsg+":"+ getStackTrace(e));
		}
	}

	private  String getStackTrace(final Throwable throwable) {
		final StringWriter sw = new StringWriter();
		final PrintWriter pw = new PrintWriter(sw, true);
		throwable.printStackTrace(pw);
		return sw.getBuffer().toString();
	}

}
